<script setup lang="ts">
import { ApiDetail } from '@/api/api-manage/detail'
import axios from 'axios'
import { message } from '@/utils/message'
import { dayjs, UploadRawFile, UploadRequestOptions } from 'element-plus'
import { ApiLogBo } from '../../type'
import { addLog } from '@/api/api-manage/log'
import { generateApiLog } from '../../useApiLog'
import { getToken } from '@/utils/auth'
import { useUserStore } from '@/store/modules/user'

const props = defineProps<{
  data: ApiDetail
}>()

type OcrLayoutBoxTuple = [number, number, number, number]

interface OcrLayoutInfo {
  bbox: OcrLayoutBoxTuple
  type: string
  res: string
}

const rectangleColorMap = new Map([
  ['title', 'red'],
  ['text', 'blue'],
  ['figure', 'yellow'],
  ['table', 'pink'],
  ['caption', 'purple'],
  ['equation', 'green'],
])

const typeToChineseMap = new Map([
  ['title', '标题'],
  ['text', '文本'],
  ['figure', '图片'],
  ['table', '表格'],
  ['caption', '说明标题'],
  ['equation', '表达式'],
])

/** 统计各类识别出来的type顺序 */
let typeStatsMap = new Map<string, number>()
/** 统计type顺序对应的文案 */
let typeToOcrTextMap = new Map<string, string>()

const fileList = ref([] as any)
const uploadRef = ref()
const textRes = ref()
const layoutTextRes = ref()
const buttonLoading = ref(false)
const textLoading = ref(false)
const isLayout = ref(false)

const canvas = ref()
const canvasWidth = ref(0)
const canvasHeight = ref(0)
const rectanglesData = ref([])
const context = ref(null)
let drawOnImg

/**
 * 上传文件方法
 * @param options
 */
const requestFile = async (options: UploadRequestOptions) => {
  if (props.data.enabledStatus != '1') {
    message('接口已停用, 请联系管理员开启', { type: 'warning' })
    return
  }
  textRes.value = ''
  layoutTextRes.value = ''
  buttonLoading.value = true
  textLoading.value = true
  const { file } = options
  const formData = new FormData()
  formData.append('file', file)
  message('正在执行OCR调用', { type: 'info' })
  let startTime = performance.now()
  const requestTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
  let res = '0'
  let resCode = 500
  axios
    .post(props.data.serverProdPath + props.data.serverUri, formData)
    .then((response) => {
      if (response.data?.data) {
        if (response.data.data === '') {
          message('成功执行OCR文本识别，但未检测到任何文本', { type: 'info' })
          isLayout.value = false
        } else if (response.data.data instanceof Array) {
          if (response.data.data.length == 0) {
            textRes.value = ''
            isLayout.value = false
            message('成功执行OCR版面识别，但未检测到任何版面信息', { type: 'info' })
          } else {
            const reader = new FileReader()
            reader.onload = () => {
              rectanglesData.value = []
              const img = new Image()
              let b64ImgWithHeader = String(reader.result)
              img.src = b64ImgWithHeader
              img.onload = function () {
                isLayout.value = true
                drawOnCanvas()
                message('OCR版面识别成功', { type: 'success' })
              }
              drawOnImg = img
              rectanglesData.value = response.data.data
            }
            reader.readAsDataURL(options.file)
          }
        } else {
          message('OCR文本识别成功', { type: 'success' })
          textRes.value = response.data.data
          isLayout.value = false
        }
      } else {
        message('成功执行OCR，但未检测到任何信息', { type: 'info' })
        isLayout.value = false
      }
      res = '1'
      resCode = 200
    })
    .catch((err) => {
      res = '0'
      resCode = 500
      message('接口存在问题无法调用', { type: 'error' })
    })
    .finally(() => {
      let endTime = performance.now()
      let duration = endTime - startTime
      const endDateTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
      let userBy = '在线体验'
      if (getToken() != null && getToken() != '') {
        userBy = useUserStore().username + userBy
      }
      const log = generateApiLog(
        props.data,
        requestTime,
        endDateTime,
        duration,
        userBy,
        res,
        resCode,
        '2'
      )
      addLog(log)
      textLoading.value = false
      buttonLoading.value = false
    })
}

const beforeUpload = (rawFile: UploadRawFile) => {
  if (rawFile.type == 'image/jpeg' || rawFile.type == 'image/png' || rawFile.type == 'image/jpg') {
    return true
  } else {
    message('请上传jpg/png图片', { type: 'warning' })
    return false
  }
}

const drawOnCanvas = () => {
  context.value = canvas.value.getContext('2d')
  // 画布大小比图片大小略大一些，方便在边界填充OCR提示文字，每次变更画布大小都会重置canvas
  canvas.value.width = drawOnImg.width + 60
  canvas.value.height = drawOnImg.height + 5
  const ctx = context.value
  if (ctx) {
    typeStatsMap = new Map()
    typeToOcrTextMap = new Map()
    ctx.clearRect(0, 0, canvasWidth.value, canvasHeight.value)
    ctx.drawImage(drawOnImg, 0, 5, drawOnImg.width, drawOnImg.height)
    layoutTextRes.value = ''
    // 遍历矩形数据并绘制
    rectanglesData.value.forEach((item: OcrLayoutInfo) => {
      if (typeStatsMap.has(item.type)) {
        typeStatsMap.set(item.type, typeStatsMap.get(item.type) + 1)
      } else {
        typeStatsMap.set(item.type, 1)
      }
      typeToOcrTextMap.set(typeToChineseMap.get(item.type) + typeStatsMap.get(item.type), item.res)
      const [left, top, right, bottom] = item.bbox
      const width = right - left
      const height = bottom - top
      const type = item.type

      // 绘制矩形
      ctx.strokeStyle = rectangleColorMap.get(type)
      ctx.lineWidth = 2
      ctx.strokeRect(left, top + 5, width, height)

      // 绘制文本
      ctx.fillStyle = rectangleColorMap.get(type)
      ctx.font = '14px Arial'
      const textX = right + 8
      const textY = 5 + top + (bottom - top) / 2
      let typeTranslate = ''
      if (typeToChineseMap.has(type)) {
        typeTranslate = typeToChineseMap.get(type) + typeStatsMap.get(item.type)
      } else {
        typeTranslate = type
      }
      ctx.fillText(typeTranslate, textX, textY)
    })
    // 展示在文本框的ocr详细内容
    typeToOcrTextMap.forEach((v, k) => {
      layoutTextRes.value = layoutTextRes.value + k + '：' + v + '\n\n'
    })
  }
}
</script>

<template>
  <el-scrollbar>
    <div>
      <el-upload
        ref="uploadRef"
        action="#"
        :file-list="fileList"
        :show-file-list="false"
        :http-request="requestFile"
        accept=".jpg, .png, .jpeg"
        :before-upload="beforeUpload"
      >
        <el-button v-loading="buttonLoading" type="primary">上传图片</el-button>
      </el-upload>
      <br />
      <el-form>
        <el-form-item v-if="!isLayout" v-loading="textLoading" label="OCR结果">
          <el-input v-model="textRes" type="textarea" :rows="8" />
        </el-form-item>
        <el-row v-show="isLayout" :gutter="16">
          <el-col :span="8">
            <el-form-item v-show="isLayout" v-loading="textLoading" label="OCR文字识别结果">
              <el-input v-model="layoutTextRes" type="textarea" :rows="20" />
            </el-form-item>
          </el-col>
          <el-col :span="16">
            <el-form-item v-show="isLayout" v-loading="textLoading" label="OCR版面图">
              <canvas ref="canvas" />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
    </div>
  </el-scrollbar>
</template>
